package delivery

import (
	"context"
	"errors"
	"github.com/google/uuid"
	"github.com/shopspring/decimal"
	"gorm.io/gorm"
	"insighttracking/apps/sorting/auth"
	"insighttracking/common/enum"
	"insighttracking/common/utils"
	"insighttracking/query/dao"
	"insighttracking/query/model"
	"insighttracking/query/service"
	"net/http"
	"strconv"
	"strings"
	"time"

	"insighttracking/apps/sorting/internal/svc"
	"insighttracking/apps/sorting/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
	"os"
)

type ApiLogic struct {
	logx.Logger
	ctx     context.Context
	svcCtx  *svc.ServiceContext
	Request *http.Request
}

func NewApiLogic(ctx context.Context, svcCtx *svc.ServiceContext, request *http.Request) *ApiLogic {
	hostname, _ := os.Hostname()
	return &ApiLogic{
		Logger: logx.WithContext(ctx).WithCallerSkip(0).WithFields(
			logx.Field("Log_UUID", uuid.New().String()),
			logx.Field("hostname", hostname)),
		ctx:     ctx,
		svcCtx:  svcCtx,
		Request: request,
	}
}

func (l *ApiLogic) GetOrdersApi() (resp *types.DeliveryOrdersResp, err error) {
	resp = &types.DeliveryOrdersResp{}
	accountInfo, err := auth.GetAccountInfo(l.svcCtx, l.Request)
	if err != nil {
		return
	}

	entities, err := service.OrdersService.GetUnshippedListApi(l.ctx, accountInfo.EnterpriseId)
	if err != nil {
		return
	}
	list := make([]*types.DeliveryOrdersList, 0)
	for _, v := range entities {
		customerName, _ := service.EnterpriseCustomerService.GetNameByIdApi(l.ctx, v.CustomerID)
		list = append(list, &types.DeliveryOrdersList{
			CreatedAt:     utils.TimestampToString(v.CreatedAt),
			CustomerName:  customerName,
			OrdersID:      v.ID,
			SendGoodsDate: utils.TimestampToString(v.SendGoodsDate),
			Status:        v.Status,
		})
	}
	resp.List = list
	return
}

func (l *ApiLogic) GetSpuApi() (resp *types.DeliverySpuResp, err error) {
	resp = &types.DeliverySpuResp{}
	accountInfo, err := auth.GetAccountInfo(l.svcCtx, l.Request)
	if err != nil {
		return
	}

	entities, err := service.OrdersService.GetUnshippedListApi(l.ctx, accountInfo.EnterpriseId)
	if err != nil {
		return
	}
	ordersIDs := make([]int64, 0)
	for _, v := range entities {
		ordersIDs = append(ordersIDs, v.ID)
	}

	spuGroups, err := service.OrdersSpuService.GetSpuListByIDApi(l.ctx, ordersIDs)
	list := make([]*types.DeliverySpuList, 0)
	for _, v := range spuGroups {
		var packedWeight decimal.Decimal
		idsString := strings.Split(v.ID, ",")
		var ids []int64
		// 遍历分割后的字符串切片，将每个字符串转换为 int64
		for _, s := range idsString {
			id, _ := strconv.ParseInt(s, 10, 64)
			ids = append(ids, id)
		}
		packedWeight, _ = service.ProductionSortingService.GetSpuSortedWeight(l.ctx, ids)
		list = append(list, &types.DeliverySpuList{
			PackedWeight:    packedWeight.InexactFloat64(),
			ProductImageURL: v.ProductImageURL,
			RequireCount:    v.RequireCount.InexactFloat64(),
			SpuID:           v.SpuID,
			SpuName:         v.SpuName,
		})
	}
	resp.List = list
	return
}

func (l *ApiLogic) GetOrdersSpuApi(req *types.OrdersIDForm) (resp *types.DeliveryOrdersSpuResp, err error) {
	resp = &types.DeliveryOrdersSpuResp{}

	entities, err := service.OrdersSpuService.GetListByOrdersIDApi(l.ctx, req.OrdersID)
	if err != nil {
		return
	}

	list := make([]*types.DeliveryOrdersSpuList, 0)
	for _, v := range entities {
		var packageCount int64
		packageCount, _ = service.ProductionSortingService.GetPackedCount(l.ctx, v.ID)
		list = append(list, &types.DeliveryOrdersSpuList{
			CategoryID:      v.CatogoryID,
			CategoryName:    v.CatogoryName,
			ID:              v.ID,
			PackageCount:    packageCount,
			ProductImageURL: v.ProductImageURL,
			RequireCount:    v.RequireCount.InexactFloat64(),
			SalesPrice:      v.SalsePrice.InexactFloat64(),
			SpuID:           v.SpuID,
			SpuName:         v.SpuName,
			Status:          v.DeliveryStatus,
			UnitID:          v.UnitID,
			UnitName:        v.UnitName,
		})
	}
	resp.List = list
	return
}

func (l *ApiLogic) GetSpuOrdersApi(req *types.SpuIDForm) (resp *types.DeliverySpuOrdersResp, err error) {
	resp = &types.DeliverySpuOrdersResp{}

	accountInfo, err := auth.GetAccountInfo(l.svcCtx, l.Request)
	if err != nil {
		return
	}

	entities, err := service.OrdersService.GetUnshippedListApi(l.ctx, accountInfo.EnterpriseId)
	if err != nil {
		return
	}
	ordersIDs := make([]int64, 0)
	for _, v := range entities {
		ordersIDs = append(ordersIDs, v.ID)
	}

	spuOrders, err := service.OrdersSpuService.GetSpuOrdersListApi(l.ctx, ordersIDs, req.SpuID)
	list := make([]*types.DeliverySpuOrdersList, 0)
	for _, v := range spuOrders {
		orders, _ := service.OrdersService.GetDetailByIdApi(l.ctx, v.OrdersID)
		var packedWeight float64
		var packedCount int64
		packedWeight, _ = service.ProductionSortingService.GetPackedWeight(l.ctx, v.ID)
		packedCount, _ = service.ProductionSortingService.GetPackedCount(l.ctx, v.ID)
		list = append(list, &types.DeliverySpuOrdersList{
			CustomerName:  orders.CustomerName,
			ID:            v.ID,
			OrdersNo:      orders.OrderNo,
			PackageCount:  packedCount,
			PackageWeight: packedWeight,
			RequireCount:  v.RequireCount.InexactFloat64(),
			UnitName:      v.UnitName,
			SpuID:         v.SpuID,
			Status:        v.DeliveryStatus,
		})
	}
	resp.List = list
	return
}

func (l *ApiLogic) GetPackApi(req *types.OrdersSpuIDForm) (resp *types.DeliveryPackResp, err error) {
	resp = &types.DeliveryPackResp{}
	accountInfo, err := auth.GetAccountInfo(l.svcCtx, l.Request)
	if err != nil {
		return
	}
	ordersSpu, err := service.OrdersSpuService.GetByIDApi(l.ctx, req.OrdersSpuID)
	if err != nil {
		return
	}
	entities, err := service.ProductionSortingService.GetUnshippedPackedList(l.ctx, accountInfo.EnterpriseId, ordersSpu.SpuID)
	if err != nil {
		return
	}

	list := make([]*types.DeliveryPackList, 0)
	for _, v := range entities {
		isSelf := false
		if v.OrdersSpuID == req.OrdersSpuID {
			isSelf = true
		}
		list = append(list, &types.DeliveryPackList{
			CreatedAt:             utils.TimestampToString(v.CreatedAt),
			Deviation:             v.Deviation.InexactFloat64(),
			ProductionBatchNumber: v.ProductionBatchNumber,
			Status:                v.Status,
			Weight:                v.Weight.InexactFloat64(),
			IsSelf:                isSelf,
		})
	}
	resp.List = list
	return
}

func (l *ApiLogic) PostPackApi(req *types.DeliveryPackReq) (resp string, err error) {
	err = service.ProductionSortingService.BindOne(l.ctx, req.ProductionBatchNumber, req.ID)
	if err != nil {
		return
	}
	return "success", nil
}

func (l *ApiLogic) PutPackApi(req *types.ProductionBatchNumberJson) (resp string, err error) {
	err = service.ProductionSortingService.UnBindOne(l.ctx, req.ProductionBatchNumber)
	if err != nil {
		return
	}
	return "success", nil
}

func (l *ApiLogic) SendApi(req *types.IDJson) (resp string, err error) {
	ordersSpu, err := service.OrdersSpuService.GetByIDApi(l.ctx, req.ID)
	if err != nil {
		return
	}

	accountInfo, err := auth.GetAccountInfo(l.svcCtx, l.Request)
	if err != nil {
		return
	}

	tx := dao.Use(l.svcCtx.MysqlDb).Begin()
	modifyStatus := map[string]any{
		"delivery_status": 20,
		"delivery_time":   time.Now(),
	}

	// 修改订单明细状态
	if err = service.OrdersSpuService.ModifyByIDApi(l.ctx, tx, req.ID, modifyStatus); err != nil {
		if err = tx.Rollback(); err != nil {
			return
		}
	}

	// 修改包裹状态
	if err = service.ProductionSortingService.OutSendByOrdersSpuIDApi(l.ctx, tx, req.ID); err != nil {
		if err = tx.Rollback(); err != nil {
			return
		}
	}

	ordersID := ordersSpu.OrdersID

	//减少成品库存
	warehouse, _ := service.WarehouseService.GetWarehouseByEnterpriseDefaultIdApi(l.ctx, accountInfo.EnterpriseId)

	var weight decimal.Decimal
	packageList, _ := service.ProductionSortingService.GetPackedList(l.ctx, req.ID)
	entities := make([]*model.InventoryRecordEntity, 0)
	for _, pack := range packageList {
		entities = append(entities, &model.InventoryRecordEntity{
			EnterpriseID: accountInfo.EnterpriseId,   // 关联到enterprise表主键id
			SpuID:        pack.SpuID,                 // 商品主键,关联到spu表主键id
			Types:        1,                          // 类型,0表示入库,1表示出库
			Source:       20,                         // 来源,0表示正常采购出入口,10表示生产分拣出入口,20表示发货出库出入口,30表示系统操作
			WarehouseID:  warehouse.ID,               // 仓库id,关联到warehouse表主键id
			ChangeCount:  pack.Weight,                // 变动数量
			ShelfID:      0,                          // 货位ID
			BatchNumber:  pack.ProductionBatchNumber, // 批次号,订单号
		})
		weight = weight.Add(pack.Weight)
	}

	if err = service.InventRecordService.BatchCreateInventRecordApi(l.ctx, tx, entities); err != nil {
		if err = tx.Rollback(); err != nil {
			return
		}
	}

	err = service.SpuInventoryService.ReduceInventoryApi(l.ctx, tx, accountInfo.EnterpriseId, warehouse.ID, ordersSpu.SpuID, weight)
	if err != nil {
		if err = tx.Rollback(); err != nil {
			return
		}
	}

	if err = tx.Commit(); err != nil {
		return
	}

	// 查询是否全部发货
	ordersSpus, err := service.OrdersSpuService.GetUnshippedListByOrdersIDApi(l.ctx, ordersID)
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		return
	}

	if errors.Is(err, gorm.ErrRecordNotFound) || len(ordersSpus) == 0 {
		if err = service.OrdersService.ModifyStatusByIdApi(l.ctx, nil, []int64{ordersID}, enum.OrdersAlreadyShippedEnum); err != nil {
			return
		}
	}

	if ordersSpu.RequireCount.Compare(weight) > 0 {
		// TODO 告警信息
	}
	return
}

func (l *ApiLogic) GetLabelListApi(req *types.SpuIDForm) (resp *types.DeliveryLabelResp, err error) {
	resp = &types.DeliveryLabelResp{}
	accountInfo, err := auth.GetAccountInfo(l.svcCtx, l.Request)
	if err != nil {
		return
	}
	entities, err := service.ProductionSortingService.GetUnshippedPackedList(l.ctx, accountInfo.EnterpriseId, req.SpuID)
	if err != nil {
		return
	}

	list := make([]*types.DeliveryLabelList, 0)
	for _, v := range entities {
		spu, _ := service.SpuService.GetSpuDetailByIdApi(l.ctx, v.SpuID)
		list = append(list, &types.DeliveryLabelList{
			CreatedAt:             utils.TimestampToString(v.CreatedAt),
			Deviation:             v.Deviation.InexactFloat64(),
			ProductionBatchNumber: v.ProductionBatchNumber,
			Status:                v.Status,
			Weight:                v.Weight.InexactFloat64(),
			SpuName:               spu.Name,
			SpuType:               spu.SpuType,
			UnitName:              spu.UnitName,
		})
	}
	resp.List = list
	return
}
